/**
 * 飞行
 */

import * as THREE from '../threejs/build/three.module.js';
import { TWEEN } from '../threejs/js/libs/tween.module.min.js';

class Fly {
    constructor(controls, camera) {
        this.camera = camera;
        this.controls = controls;

        this._pathIndex = 0;
        this._isFly = false;
    }

    fly(path) {
        if (path) {
            this._path = path;
            this._isFly = true;
            this._pathIndex = 0;
        }

        if (!this._isFly) {
            return;
        }

        console.log("飞行：" + this._pathIndex);

        if (this._pathIndex == this._path.length) {
            this._isFly = false;
            TWEEN.remove(this.tween);
            this.controls.target.copy(this.controls.getTarget(3000));
            return;
        }

        if (this._path[this._pathIndex].turn) {
            this.turn(this._path[this._pathIndex].angle, () => {
                this._pathIndex++;
                this.fly();
            });
        } else {
            this.moveCamera(this._path[this._pathIndex].position, this._path[this._pathIndex].target, function () {
                this._pathIndex++;
                this.fly();
            });
        }
    }

    moveCamera(position, target, callback) {
        let distance = 500;
        if (this._pathIndex > 0) {
            let preIndex = this._pathIndex - 1;
            if (this._path[preIndex].turn) {
                preIndex -= 1;
            }
            distance = this.distance(this._path[preIndex].position, this._path[this._pathIndex].position);
            if (distance < 500)
                distance = 500;
        }

        let time = 0;
        if (this._pathIndex == 0) {
            time = 1;
        } else if (this._pathIndex == 1) {
            time = distance * 2;
        } else {
            time = distance * 2;
            //time = 3000;
        }
        console.log("time=" + time);

        let currentTarget = target;
        this.tween2 = new TWEEN.Tween(this.controls.target).to({
            x: target[0],
            y: target[1],
            z: target[2]
        }, 3000).start().onUpdate(e => {
            currentTarget = [e.x, e.y, e.z];
        }).onComplete(() => {
            TWEEN.remove(this.tween2);
        });

        this.tween = new TWEEN.Tween(this.camera.position).to({
            x: position[0],
            y: position[1],
            z: position[2]
        }, time).start().onUpdate(() => {
            this.controls.target.set(...currentTarget);
            this.controls.update();
        }).onComplete(() => {
            TWEEN.remove(this.tween);
            callback && typeof callback === 'function' && callback();
        });
    }

    moveCameraOnly(position, target, callback) {
        this._isFly = true;

        let currentTarget = target;
        this.tween2 = new TWEEN.Tween(this.controls.target).to({
            x: target[0],
            y: target[1],
            z: target[2]
        }, 3000).start().onUpdate(e => {
            currentTarget = [e.x, e.y, e.z];
        }).onComplete(() => {
            TWEEN.remove(this.tween2);
        });

        this.tween = new TWEEN.Tween(this.camera.position).to({
            x: position[0],
            y: position[1],
            z: position[2]
        }, 3000).start().onUpdate(e => {
            this.controls.target.set(...currentTarget);
            this.controls.update();
        }).onComplete(() => {
            this._isFly = false;
            TWEEN.remove(this.tween);
            callback && typeof callback === 'function' && callback();
        });
    }

    refresh() {
        this._isFly && TWEEN.update();
    }

    distance(pos1, pos2) {
        return Math.sqrt(Math.pow(pos1[0] - pos2[0], 2) + Math.pow(pos1[1] - pos2[1], 2) + Math.pow(pos1[2] - pos2[2], 2));
    }

    turn(angle, callback) {
        this._isFly = true;

        let eulerOld = new THREE.Euler(0, 0, 0, 'YXZ');
        eulerOld.setFromQuaternion(this.camera.quaternion);

        let euler = new THREE.Euler(0, 0, 0, 'YXZ');
        euler.setFromQuaternion(this.camera.quaternion);

        angle = angle * Math.PI / 180;
        euler.y -= angle;

        let tween = new TWEEN.Tween(eulerOld).to({
            x: euler.x,
            y: euler.y,
            z: euler.z
        }, 1000).start().onUpdate((e) => {
            this.camera.quaternion.setFromEuler(e);
            this.controls.target.copy(this.controls.getTarget(3000));
            this.controls.update();
        }).onComplete(() => {
            TWEEN.remove(tween);
            callback && callback();
        });

    }

    stop() {
        this._isFly = false;
    }
}

export { Fly }
